#!/usr/bin/env python
# utils/update-checkout - Utility to update your local checkouts -*- python -*-
#
# This source file is part of the Swift.org open source project
#
# Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
# Licensed under Apache License v2.0 with Runtime Library Exception
#
# See http://swift.org/LICENSE.txt for license information
# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors

from __future__ import print_function

import argparse
import os
import sys

sys.path.append(os.path.dirname(__file__))

from SwiftBuildSupport import (
    SWIFT_SOURCE_ROOT,
    WorkingDirectory,
    check_call,
    check_output,
)  # noqa (E402 module level import not at top of file)

REPOSITORIES = {
    'llvm': 'apple/swift-llvm',
    'clang': 'apple/swift-clang',
    'swift': 'apple/swift-swift',
    'lldb': 'apple/swift-lldb',
    'cmark': 'apple/swift-cmark',
    'llbuild': 'apple/swift-llbuild',
    'swiftpm': 'apple/swift-package-manager',
    'compiler-rt': 'apple/swift-compiler-rt',
    'swift-corelibs-xctest': 'apple/swift-corelibs-xctest',
    'swift-corelibs-foundation': 'apple/swift-corelibs-foundation',
    'swift-corelibs-libdispatch': 'apple/swift-corelibs-libdispatch',
    'swift-integration-tests': 'apple/swift-integration-tests',
}

NEXT_BRANCHES = {
    'llvm': 'stable-next',
    'clang': 'stable-next',
    'swift': 'master-next',
    'lldb': 'master-next',
    'cmark': 'master',
    'llbuild': 'master',
    'swiftpm': 'master',
    'swift-corelibs-xctest': 'master',
    'swift-corelibs-foundation': 'master',
    'swift-corelibs-libdispatch': 'master',
    'swift-integration-tests': 'master',
}


def update_working_copy(repo_path, branch):
    if not os.path.isdir(repo_path):
        return

    print("--- Updating '" + repo_path + "' ---")
    with WorkingDirectory(repo_path):
        if branch:
            status = check_output(['git', 'status', '--porcelain'])
            if status:
                print("Please, commit your changes.")
                print(status)
                exit(1)
            check_call(['git', 'checkout', branch])

        # Prior to Git 2.6, this is the way to do a "git pull
        # --rebase" that respects rebase.autostash.  See
        # http://stackoverflow.com/a/30209750/125349
        check_call(["git", "fetch"])
        check_call(["git", "rebase", "FETCH_HEAD"])


def obtain_additional_swift_sources(
        with_ssh, branch, skip_history, skip_repositories):
    for dir_name, repo in REPOSITORIES.items():
        if dir_name in skip_repositories:
            print("--- Skipping '" + dir_name + "' ---")
            continue
        with WorkingDirectory(SWIFT_SOURCE_ROOT):
            if not os.path.isdir(os.path.join(dir_name, ".git")):
                print("--- Cloning '" + dir_name + "' ---")
                if with_ssh is True:
                    remote = "git@github.com:" + repo + '.git'
                else:
                    remote = "https://github.com/" + repo + '.git'
                if skip_history:
                    check_call(['git', 'clone', '--recursive', '--depth', '1',
                                remote, dir_name])
                else:
                    check_call(['git', 'clone', '--recursive', remote,
                                dir_name])
                if branch:
                    if branch == "stable-next" or branch == "master-next":
                        repo_branch = NEXT_BRANCHES[dir_name]
                    else:
                        repo_branch = branch
                    src_path = SWIFT_SOURCE_ROOT + "/" + dir_name + "/" + \
                        ".git"
                    check_call(['git', '--git-dir', src_path, '--work-tree',
                                os.path.join(SWIFT_SOURCE_ROOT, dir_name),
                                'checkout', repo_branch])


def main():
    parser = argparse.ArgumentParser(
        formatter_class=argparse.RawDescriptionHelpFormatter,
        description="""
repositories.

By default, updates your checkouts of Swift, SourceKit, LLDB, and SwiftPM.""")
    parser.add_argument(
        "--clone",
        help="Obtain Sources for Swift and Related Projects",
        action="store_true")
    parser.add_argument(
        "--clone-with-ssh",
        help="Obtain Sources for Swift and Related Projects via SSH",
        action="store_true")
    parser.add_argument(
        "--skip-history",
        help="Skip histories when obtaining sources",
        action="store_true")
    parser.add_argument(
        "--skip-repository",
        metavar="DIRECTORY",
        default=[],
        help="Skip the specified repository",
        action="append")
    parser.add_argument(
        "--branch",
        help="Obtain Sources for specific branch")
    args = parser.parse_args()

    clone = args.clone
    clone_with_ssh = args.clone_with_ssh
    skip_history = args.skip_history
    branch = args.branch

    if clone or clone_with_ssh:
        obtain_additional_swift_sources(
            clone_with_ssh, branch, skip_history, args.skip_repository)

    repo_branch = branch
    for dir_name, _ in REPOSITORIES.items():
        if dir_name in args.skip_repository:
            print("--- Skipping '" + dir_name + "' ---")
            continue
        if branch:
            if branch == "stable-next" or branch == "master-next":
                repo_branch = NEXT_BRANCHES[dir_name]

        update_working_copy(os.path.join(SWIFT_SOURCE_ROOT, dir_name),
                            repo_branch)

    return 0


if __name__ == "__main__":
    sys.exit(main())
